from django.shortcuts import render

# Create your views here.
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.views import APIView

from .models import Person, ContactRel
from . import utils
from . import error_utils
from neomodel import db

"""对两个人的关系进行修改"""


class ContactNetworkView(APIView):
    # todo 如果吧person_set放在这里会经常找不到。 很奇怪

    def get(self, request):
        """
        查询两个人的接触网络
        :param request:
        :return:
        """
        # 定义一个查询格式
        data = request.query_params  # 查询字符串
        # data
        o_node_id = data.get('o_node_id')
        s_node_id = data.get('s_node_id')
        try:
            s_person = Person.nodes.get(node_id=s_node_id)  # 每次fiter都会对person_ser进行筛选， 返回筛选的值
        except Person.DoesNotExist:
            not_found_msg = f'没找到节点id为{s_node_id}的用户'
            return Response(error_utils.not_found_msg(not_found_msg))

        try:
            o_person = Person.nodes.get(node_id=o_node_id)
        except Person.DoesNotExist:
            not_found_msg = f'没找到节点id为{o_node_id}的用户'
            return Response(error_utils.not_found_msg(not_found_msg))

        rels = s_person.contact.relationship(o_person)
        if not rels:
            return Response(error_utils.not_found_msg('这两个用户之间没有关系'))
        return Response({
            'code': '200',
            'data': rels.serialize
        })
        pass

    def person_2_person(self, data):
        o_node_id = data.get('o_node_id')
        s_node_id = data.get('s_node_id')
        rel_info = data.get('rel_info')
        return utils.create_rel(o_node_id=o_node_id, s_node_id=s_node_id, rel_info=rel_info)

    def post(self, request):
        """
        创建两个节点之间的关系
        :param request:
        :return:
        """
        data = request.data
        create_info_list = data.get('data', None)
        if not create_info_list:
            res_data = self.person_2_person(data)
            return Response(res_data)
            pass

        i = 0
        for create_info in create_info_list:
            s_mobile = create_info.get('s_mobile')
            o_mobile = create_info.get('o_mobile')
            rel_info = create_info.get('rel_info')
            utils.create_rel_by_mobile(s_mobile=s_mobile, o_mobile=o_mobile, rel_info=rel_info)
            i += 1
            print(f'创建了{i}条关系', create_info)

        return Response({
            'code': '200'
        })
        # todo 建立关系接口
        pass

    def delete(self, request):
        """
        删除关系
        :param request:
        :return:
        """
        data = request.data
        s_mobile = data.get('s_mobile')
        o_mobile = data.get('o_mobile')

        s_person = Person.nodes.get(mobile=s_mobile)
        o_person = Person.nodes.get(mobile=o_mobile)
        rels = s_person.contact.relationship(o_person)
        s_person.contact.disconnect(o_person)
        res_data = rels.serialize
        return Response({
            'code': '200',
            'data': res_data
        })
        pass

    def put(self, request):
        # 定义一个查询格式
        data = request.data  # 查询字符串
        s_mobile = data.get('s_mobile')
        o_mobile = data.get('o_mobile')
        degree = data.get('degree')
        location_id = data.get('location_id')

        try:
            s_person = Person.nodes.get(mobile=s_mobile)  # 每次fiter都会对person_ser进行筛选， 返回筛选的值
        except Person.DoesNotExist:
            not_found_msg = f'没找到电话号码为{s_mobile}的用户'
            return Response(error_utils.not_found_msg(not_found_msg))

        try:
            o_person = Person.nodes.get(mobile=o_mobile)
        except Person.DoesNotExist:
            not_found_msg = f'没找到电话号码为{o_mobile}的用户'
            return Response(error_utils.not_found_msg(not_found_msg))

        # 更新
        rels = s_person.contact.relationship(o_person)

        if not rels:
            return Response(error_utils.not_found_msg('这两个用户之间没有关系'))
        rels.update(location_id, degree)
        return Response(
            {
                "code": "200",
                'data': rels.serialize
            }
        )
        pass


# 人删除改
class PersonListView(APIView):
    queryset = Person.nodes

    def post(self, request):
        """
        添加人物信息
        :param request:
        :return:
        """
        data = request.data
        persons_info_list = data.get('data')
        i = 1
        for person_info in persons_info_list:
            try:
                person = Person(**person_info).save()
                i += 1
                print(f'创建了{i}个人')
            except Exception as e:
                print(e, f"卡号{person_info.get('card_id')}已存在")

        return Response({
            'code': '200',
        })

    def get(self, request):
        """
        获取人， 可以按照一定的查询字符串
        :param request:
        :return:
        """
        fetch_info = {
            'node_type': Person,
            'mobile': request.GET.get('mobile', ''),
            'name': request.GET.get('name', ''),
            'permanent_residence': request.GET.get('permanent_residence', ''),
            'status': request.GET.get('status', ''),
            'card_id': request.GET.get('card_id', ''),
        }
        node_data = utils.filter_nodes(**fetch_info)
        if type(node_data) == str:  # 如果没找到
            return Response({
                'code': '201',
                'msg': node_data
            })
        return Response({
            'code': '200',
            'data': node_data
        })


class PersonDetailView(APIView):

    def put(self, request, mobile):
        """
        根据电话号码，卡号
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        res = {}
        update_info = {
            'name': request.data.get('name', ''),
            'permanent_residence': request.data.get('permanent_residence', ''),
            'status': request.data.get('status', ''),
            'img': request.data.get('img', ''),
            'card_id': request.data.get('card_id', ''),
            'mobile': mobile
        }

        person = Person.nodes.get_or_none(mobile=mobile)
        if not person:
            res['code'] = '201'
            res['msg'] = f'没有号码为{mobile}的用户'
            return Response(res)
        person.update(**update_info)
        res['code'] = '200'
        res['data'] = person.serialize
        return Response(res)


class NetWorkView(APIView):

    def get(self, request):
        """
        创建
        :param request:
        :param id:
        :return:
        """
        data = request.query_params  # 查询字符串
        # node_id = str(data.get('node_id'))

        # data
        fetch_info = {
            'node_id': data.get('node_id'),
            'start_time': data.get('start_time'),
            'end_time': data.get('end_time'),
        }
        data = utils.get_network(**fetch_info)
        return Response({
            'code': '200',
            'data': data
        })


class LocationDetailView(APIView):

    def get(self, request, location_id):
        cypher = f"match(p1:Person)-[r:CONTACT{{location_id: '{location_id}'}}]-(p2:Person) return distinct p1"
        result, meta = db.cypher_query(cypher)
        person_data = [Person.inflate(row[0]).serialize for row in result]
        return Response({
            'code': '200',
            'data': person_data,
            'count': len(person_data)
        })


class LocationListlView(APIView):

    def get(self, request):
        """
        统计全部地点的接触次数
        :param request:
        :param location_id:
        :return:
        """
        data = {}

        # 拿到全部位置数据
        cypher = """MATCH p=()-[r:CONTACT]->() RETURN distinct r.location_id"""
        # 循环
        rows, meta = db.cypher_query(cypher)
        for row in rows:
            location_id = row[0]
            cypher = f"""MATCH p=()-[r:CONTACT]->() where r.location_id="{location_id}" RETURN  count(r)"""
            count = db.cypher_query(cypher)[0][0][0]
            data[location_id] = count

        return Response({
            'code': '200',
            'data': data
        })


class GnderListView(APIView):

    def get(self, request):
        """
        按照性别统计
        :param request:
        :return:
        """
        data = dict(female=len(Person.nodes.filter(gender='0')),
                    male=len(Person.nodes.filter(gender='1')),
                    unknown=len(Person.nodes.filter(gender='2')),
                    )
        return Response({
            'code': '200',
            'data': data
        })


class PageRankListView(generics.GenericAPIView):

    def get(self, request):
        """

        :param request:
        :return:
        """
        cypher = """CALL gds.pageRank.stream('myGraph')
                    YIELD nodeId, score
                    RETURN gds.util.asNode(nodeId).name AS name, gds.util.asNode(nodeId).node_id AS node_id, score
                    ORDER BY score DESC, name ASC"""

        rows, meta = db.cypher_query(cypher)
        res_data = [{'name': row[0], 'id': row[1], 'degree': row[2]} for row in rows[0:10]]
        res_data = {
            'code': '200',
            'data': res_data,
        }
        return Response(res_data)


class InitNetWorkView(generics.GenericAPIView):
    def get(self, request):
        limit = request.query_params.get('limit')
        if not limit:
            limit = 100

        cypher = f"""MATCH p=(p1:Person)-[r:CONTACT]->(p2:Person)  RETURN nodes(p) as persons, relationships(p) as rels limit {limit}"""
        rows, meta = db.cypher_query(cypher)
        node_set = set()
        edge_set = set()
        for row in rows:
            nodes = row[0]
            edges = row[1]
            for node in nodes:
                node_set.add(node)
            for edge in edges:
                edge_set.add(edge)
        res_data = {}
        node_list = [Person.inflate(node).serialize for node in node_set]
        edge_list = [ContactRel.inflate(edge).serialize for edge in edge_set]
        res_data['nodes'] = node_list
        res_data['edges'] = edge_list
        return Response({
            'code': '200',
            'data': res_data
        })
